#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""更新安装器模块
负责安装下载的更新包文件"""

import os
import sys
import shutil
import subprocess
import zipfile
import tempfile
import time
import threading
from utils import Logger, FileUtils
from utils.auto_update.config_manager import UpdateConfigManager

class UpdateInstaller:
    """更新安装器
    负责安装下载的更新包文件"""
    
    def __init__(self):
        """初始化更新安装器"""
        self.config_manager = UpdateConfigManager()
        self.is_installing = False
        self._install_lock = threading.Lock()
        Logger.log_info("更新安装器初始化完成")
    
    def install_update(self, update_package_path, restart_application=True):
        """安装更新包
        
        Args:
            update_package_path: 更新包文件路径
            restart_application: 安装完成后是否重启应用程序
            
        Returns:
            bool: 是否安装成功
        """
        # 尝试获取线程锁，确保同一时间只有一个安装操作在执行
        if not self._install_lock.acquire(blocking=False):
            Logger.log_info("安装任务已经在进行中，跳过本次请求")
            return False
        
        self.is_installing = True
        
        try:
            Logger.log_info(f"开始安装更新包: {update_package_path}")
            
            # 检查更新包是否存在
            if not os.path.exists(update_package_path):
                Logger.log_error(f"更新包不存在: {update_package_path}")
                return False
            
            # 获取应用程序目录
            app_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
            Logger.log_info(f"应用程序目录: {app_dir}")
            
            # 创建临时解压目录
            with tempfile.TemporaryDirectory() as temp_dir:
                Logger.log_info(f"创建临时解压目录: {temp_dir}")
                
                # 解压更新包
                if not self._extract_update_package(update_package_path, temp_dir):
                    Logger.log_error("解压更新包失败")
                    return False
                
                # 执行更新安装
                if not self._perform_update_installation(temp_dir, app_dir):
                    Logger.log_error("执行更新安装失败")
                    return False
            
            # 更新安装历史
            self._update_installation_history()
            
            # 记录最后安装的版本
            self.config_manager.set_config("last_installed_version", self._get_version_from_package(update_package_path))
            
            Logger.log_info("更新安装完成")
            
            # 如果需要，重启应用程序
            if restart_application:
                self._restart_application(app_dir)
            
            return True
        except Exception as e:
            Logger.log_error(f"安装更新包时发生错误: {str(e)}")
            return False
        finally:
            self.is_installing = False
            self._install_lock.release()
    
    def _extract_update_package(self, package_path, target_dir):
        """解压更新包
        
        Args:
            package_path: 更新包文件路径
            target_dir: 目标解压目录
            
        Returns:
            bool: 是否解压成功
        """
        try:
            # 检查文件类型
            if package_path.lower().endswith('.zip'):
                with zipfile.ZipFile(package_path, 'r') as zip_ref:
                    zip_ref.extractall(target_dir)
                Logger.log_info("成功解压ZIP格式更新包")
                return True
            else:
                Logger.log_error(f"不支持的更新包格式: {package_path}")
                return False
        except Exception as e:
            Logger.log_error(f"解压更新包时发生错误: {str(e)}")
            return False
    
    def _perform_update_installation(self, extracted_files_dir, app_dir):
        """执行更新安装
        
        Args:
            extracted_files_dir: 解压后的文件目录
            app_dir: 应用程序目录
            
        Returns:
            bool: 是否安装成功
        """
        try:
            # 模拟更新安装过程
            # 在实际应用中，这里应该根据更新包的内容执行相应的安装逻辑
            Logger.log_info("开始执行更新安装...")
            
            # 1. 备份现有文件
            self._backup_existing_files(app_dir)
            
            # 2. 复制新文件到应用程序目录
            self._copy_new_files(extracted_files_dir, app_dir)
            
            # 3. 执行必要的升级脚本或操作
            self._execute_post_install_scripts(extracted_files_dir, app_dir)
            
            Logger.log_info("更新安装执行完成")
            return True
        except Exception as e:
            Logger.log_error(f"执行更新安装时发生错误: {str(e)}")
            # 尝试回滚到备份
            self._rollback_from_backup(app_dir)
            return False
    
    def _backup_existing_files(self, app_dir):
        """备份现有文件
        
        Args:
            app_dir: 应用程序目录
        """
        # 在实际应用中，应该备份关键文件和目录
        # 这里仅记录备份操作
        backup_dir = os.path.join(app_dir, f"backup_{int(time.time())}")
        Logger.log_info(f"创建备份目录: {backup_dir}")
        
        # 模拟备份过程
        # 在实际应用中，这里应该复制关键文件和目录到备份目录
        time.sleep(1)  # 模拟耗时操作
    
    def _copy_new_files(self, source_dir, target_dir):
        """复制新文件到应用程序目录
        
        Args:
            source_dir: 源文件目录
            target_dir: 目标目录
        """
        # 模拟复制文件过程
        # 在实际应用中，这里应该根据更新包的结构复制文件
        Logger.log_info(f"复制新文件从 {source_dir} 到 {target_dir}")
        
        # 模拟耗时操作
        time.sleep(1)
    
    def _execute_post_install_scripts(self, extracted_files_dir, app_dir):
        """执行安装后脚本
        
        Args:
            extracted_files_dir: 解压后的文件目录
            app_dir: 应用程序目录
        """
        # 模拟执行安装后脚本
        # 在实际应用中，这里应该查找并执行安装后脚本
        Logger.log_info("执行安装后脚本...")
        
        # 模拟耗时操作
        time.sleep(0.5)
    
    def _rollback_from_backup(self, app_dir):
        """从备份回滚
        
        Args:
            app_dir: 应用程序目录
        """
        # 在实际应用中，这里应该从备份恢复文件
        Logger.log_info("执行回滚操作...")
        
        # 模拟耗时操作
        time.sleep(1)
    
    def _get_version_from_package(self, package_path):
        """从更新包获取版本信息
        
        Args:
            package_path: 更新包文件路径
            
        Returns:
            str: 版本号
        """
        # 在实际应用中，应该从更新包中读取版本信息
        # 这里返回一个模拟的版本号
        return "1.1.0"
    
    def _update_installation_history(self):
        """更新安装历史"""
        # 获取当前的历史记录
        history = self.config_manager.get_config("update_history", [])
        
        # 添加新的历史记录
        new_record = {
            "version": self._get_version_from_package("dummy_path"),
            "install_time": time.strftime("%Y-%m-%d %H:%M:%S"),
            "success": True
        }
        
        history.append(new_record)
        
        # 只保留最近10条记录
        if len(history) > 10:
            history = history[-10:]
        
        # 保存更新后的历史记录
        self.config_manager.set_config("update_history", history)
    
    def _restart_application(self, app_dir):
        """重启应用程序
        
        Args:
            app_dir: 应用程序目录
        """
        Logger.log_info("准备重启应用程序...")
        
        try:
            # 获取当前Python解释器的路径
            python_path = sys.executable
            
            # 应用程序的主脚本路径
            main_script = os.path.join(app_dir, "main_window.py")
            
            # 启动新的应用程序进程
            subprocess.Popen([python_path, main_script])
            
            # 退出当前进程
            sys.exit(0)
        except Exception as e:
            Logger.log_error(f"重启应用程序失败: {str(e)}")
            # 如果重启失败，不退出当前进程

# 示例用法
if __name__ == "__main__":
    installer = UpdateInstaller()
    
    # 这里假设我们有一个模拟的更新包路径
    # 在实际使用中，应该提供真实的更新包路径
    mock_package_path = "mock_update_package.zip"
    
    # 创建一个模拟的空ZIP文件用于测试
    with zipfile.ZipFile(mock_package_path, 'w') as zip_ref:
        # 添加一个空文件
        zip_ref.writestr("README.txt", "This is a mock update package.")
    
    try:
        success = installer.install_update(mock_package_path, restart_application=False)
        if success:
            print("更新安装成功")
        else:
            print("更新安装失败")
    finally:
        # 清理测试文件
        if os.path.exists(mock_package_path):
            os.remove(mock_package_path)